package edu.whu.demo.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.*;

@Aspect
@Component
public class StopWatchAspect {

    // 统计各个API的每次调用时间
    final Map<String, List<Long>> metrics= Collections.synchronizedMap(new HashMap<>());

    // 统计异常次数
    final Map<String,Long> exceptionNumber= Collections.synchronizedMap(new HashMap<>());

    Logger logger = LoggerFactory.getLogger(getClass());

    // 考虑到可能抛出异常，因此不在@Around方法中统计时长
    private long t1 = 0;

    private long t2 = 0;

    @Pointcut("@within(org.springframework.stereotype.Service)")
    public void servicePointCut(){
    }

    @Before("servicePointCut()")
    public void recordStartTime(JoinPoint jp)
    {
        t1 = Calendar.getInstance().getTimeInMillis();
        logger.info("调用{}方法", jp.getSignature());
    }

    @After("servicePointCut()")
    public void recordEndTime(JoinPoint jp)
    {
        t2 = Calendar.getInstance().getTimeInMillis();
        long respondingTime = t2-t1;
        String methodSig=jp.getSignature().toString();
        List<Long> list = metrics.containsKey(methodSig)?metrics.get(methodSig):new ArrayList<Long>();
        list.add(respondingTime);
        metrics.put(methodSig,list);
    }
    @After("execution(* edu.whu.demo.service.IProductService.showResult(..))")
    //@After("execution(* edu.whu.demo.service.*.ProductServiceImpl.showResult(..))")
    public void calData()
    {
        for(String key: metrics.keySet())
        {
            // 最长响应时间
            long longestTime = 0;

            // 最短响应时间
            long shortestTime = 10000;

            // 平均响应时间
            long averageTime = 0;

            // 总响应时间
            long totalTime = 0;

            for (long respondingTime: metrics.get(key))
            {
                if (respondingTime > longestTime)
                {
                    longestTime = respondingTime;
                }
                if (respondingTime < shortestTime)
                {
                    shortestTime = respondingTime;
                }
                totalTime += respondingTime;
                averageTime = totalTime / metrics.get(key).size();
            }
            logger.info("对{}方法", key);
            logger.info("调用次数为：{}", metrics.get(key).size());
            logger.info("最长响应时间为：{}", longestTime);
            logger.info("最短响应时间为：{}", shortestTime);
            logger.info("平均响应时间为：{}", averageTime);
            logger.info("发生异常的次数为：{}", exceptionNumber.get(key));
        }

    }

    @AfterThrowing(pointcut = "servicePointCut()", throwing = "ex")
    public void afterPointCutThrow(JoinPoint jp, Exception ex)
    {
        String methodSig=jp.getSignature().toString();
        long base= exceptionNumber.containsKey(methodSig)?exceptionNumber.get(methodSig):0;
        exceptionNumber.put(methodSig,base+1);

        logger.error("afterThrowing:异常为{}", ex.getMessage());
    }
}
